package link_list

type MLinkList struct {
	Nlen  int64
	PNode *MNode
}

func NewMLinkList() *MLinkList {
	return &MLinkList{
		Nlen:  0,
		PNode: &MNode{},
	}
}

type MNode struct {
	IData interface{}
	Next  *MNode
}

func (l *MLinkList) Length() int64 {
	return l.Nlen
}

func (l *MLinkList) Insert(index int64, elem interface{}) bool {
	if index > l.Nlen {
		return false
	}
	if index < 0 {
		return false
	}
	iNode, ok := l.getElemWithPNode(index - 1);
	if ok == false {
		return false
	}
	node := &MNode{}
	node.IData = elem
	node.Next = iNode.Next
	iNode.Next = node
	l.Nlen++
	return true
}

func (l *MLinkList) Delete(index int64) (interface{}, bool) {
	if index > l.Nlen-1 {
		return nil, false
	}
	if index < 0 {
		return nil, false
	}
	iNode, ok := l.getElemWithPNode(index - 1);
	if ok == false {
		return nil, false
	}
	if iNode==nil || iNode.Next == nil {
		return nil, false
	}
	tempElem := iNode.Next.IData
	iNode.Next = iNode.Next.Next
	l.Nlen--
	return tempElem, false
}

func (l *MLinkList) IndexOf(elem interface{}) int64 {
	p := l.PNode.Next
	var ii int64 = 0
	for p != nil {
		if p.IData == elem {
			return ii
		}
		p = p.Next
		ii++
	}
	return -1
}

func (l *MLinkList) getElemWithPNode(index int64) (*MNode, bool) {
	if index == -1{
		return l.PNode,true
	}
	return l.GetElem(index)
}

func (l *MLinkList) GetElem(index int64) (*MNode, bool) {
	p := l.PNode.Next
	var ii int64 = 0
	for p != nil {
		if ii == index {
			return p, true
		}
		p = p.Next
		ii++
	}
	return nil, false
}

func (l *MLinkList) Traverse(callback func(interface{})) {
	p := l.PNode.Next
	for p != nil {
		callback(p.IData)
		p = p.Next
	}
}
